#pragma once

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <thread>
#include <vector>
#include "acl/acl.h"
#include "acl/acl_prof.h"
#include "hccl/hccl.h"
#include "hccl/hccl_types.h"

#define MB (1024 * 1024)
#define GB (1024 * 1024 * 1024)

#define ACLCHECK(ret)                                                                         \
    do {                                                                                      \
        if (ret != ACL_SUCCESS) {                                                             \
            printf("acl interface return err %s:%d retcode: %d \n", __FILE__, __LINE__, ret); \
            return ret;                                                                       \
        }                                                                                     \
    } while (0)

#define HCCLCHECK(ret)                                                                          \
    do {                                                                                        \
        if (ret != HCCL_SUCCESS) {                                                              \
            printf("hccl interface return err %s:%d, retcode: %d \n", __FILE__, __LINE__, ret); \
            return ret;                                                                         \
        }                                                                                       \
    } while (0)

#define HCCLROOTRANKCHECK(ret)                                                                            \
    do {                                                                                                  \
        if (ret != HCCL_SUCCESS && ret != HCCL_E_PARA) {                                                  \
            printf("hccl interface return errreturn err %s:%d, retcode: %d \n", __FILE__, __LINE__, ret); \
            return ret;                                                                                   \
        }                                                                                                 \
    } while (0)

struct ThreadContext {
    size_t ndev;
    HcclComm comm;
    int32_t device;
};

std::string GetSizeStr(double size_byte) {
    size_t unit_index = 0;
    std::ostringstream capacity_str;
    std::vector<std::string> const units = {" Byte", " kB", " MB", " GB", " TB", " PB"};
    while (size_byte > 1024 && unit_index < units.size() - 1) {
        size_byte /= 1024.0;
        unit_index++;
    }
    capacity_str << std::fixed << std::setprecision(2) << size_byte << units[unit_index];
    return capacity_str.str();
}

std::string GetBandwidthStr(double bandwidth_Gbps) {
    size_t unit_index = 2;
    std::ostringstream bandwidth_str;
    std::vector<std::string> const units = {" Byte/s", " KiB/s", " GiB/s", " TiB/s", " PiB/s"};
    double bandwidth = bandwidth_Gbps;
    while (bandwidth > 1024 && unit_index < units.size() - 1) {
        bandwidth /= 1024.0;
        unit_index++;
    }
    while (bandwidth < 1 && unit_index >= 0) {
        if (bandwidth == 0) break;
        bandwidth *= 1024;
        unit_index--;
    }
    bandwidth_str << std::fixed << std::setprecision(2) << bandwidth << units[unit_index];
    return bandwidth_str.str();
}